Repository navigation
Add JSON output to GraphiQL commands - #8974
gonzaloriestra wants to merge 13 commits into
Conversation
|
/snapit |
|
🫰✨ Thanks @gonzaloriestra! Your snapshot has been published to npm. Built from Test the snapshot by installing your package globally: pnpm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20261022150917Caution After installing, validate the version by running |
| .regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/) | ||
| .describe('Normalized store hostname, including local development domains.') |
There was a problem hiding this comment.
I don't think this regex really provides any useful information. a store domain is just a string
There was a problem hiding this comment.
Actually, it should always end with myshopify.com. I've extracted the regex to a shared place to make it consistent for all commands.
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationspackages/cli-kit/dist/public/node/graphiql/schema.d.tsimport { type InferJsonOutputSchema } from '../json-output-schema.js';
import { zod } from '../schema.js';
/** Lifecycle records written as JSONL by the standalone GraphiQL commands. */
export declare const graphiqlJsonOutputSchema: import("../json-output-schema.js").JsonOutputSchema<zod.ZodDiscriminatedUnion<"type", [zod.ZodObject<{
type: zod.ZodLiteral<"starting">;
timestamp: zod.ZodString;
storeDomain: zod.ZodNullable<zod.ZodString>;
}, "strict", zod.ZodTypeAny, {
type: "starting";
timestamp: string;
storeDomain: string | null;
}, {
type: "starting";
timestamp: string;
storeDomain: string | null;
}>, zod.ZodObject<{
type: zod.ZodLiteral<"ready">;
timestamp: zod.ZodString;
url: zod.ZodString;
storeDomain: zod.ZodNullable<zod.ZodString>;
api: zod.ZodLiteral<"admin">;
apiVersion: zod.ZodNullable<zod.ZodString>;
mutationsAllowed: zod.ZodBoolean;
app: zod.ZodNullable<zod.ZodObject<{
name: zod.ZodString;
url: zod.ZodString;
}, "strict", zod.ZodTypeAny, {
name: string;
url: string;
}, {
name: string;
url: string;
}>>;
}, "strict", zod.ZodTypeAny, {
type: "ready";
url: string;
timestamp: string;
app: {
name: string;
url: string;
} | null;
api: "admin";
storeDomain: string | null;
apiVersion: string | null;
mutationsAllowed: boolean;
}, {
type: "ready";
url: string;
timestamp: string;
app: {
name: string;
url: string;
} | null;
api: "admin";
storeDomain: string | null;
apiVersion: string | null;
mutationsAllowed: boolean;
}>, zod.ZodObject<{
type: zod.ZodLiteral<"stopped">;
timestamp: zod.ZodString;
reason: zod.ZodEnum<["cancelled", "sigint", "sigterm", "sigquit"]>;
}, "strict", zod.ZodTypeAny, {
type: "stopped";
timestamp: string;
reason: "cancelled" | "sigint" | "sigterm" | "sigquit";
}, {
type: "stopped";
timestamp: string;
reason: "cancelled" | "sigint" | "sigterm" | "sigquit";
}>]>>;
type WithoutTimestamp<T> = T extends unknown ? Omit<T, 'timestamp'> : never;
type GraphiQLRecord = InferJsonOutputSchema<typeof graphiqlJsonOutputSchema>;
export type GraphiQLRecordInput = WithoutTimestamp<GraphiQLRecord>;
export {};
Existing type declarationspackages/cli-kit/dist/public/common/json-output-schema.d.ts@@ -1,4 +1,5 @@
import { z } from 'zod';
+export declare const jsonOutputStoreDomainSchema: z.ZodString;
/** UTC instants in CLI-owned JSON use whole seconds and the Z timezone marker. */
export declare const jsonOutputTimestampSchema: z.ZodString;
/**
packages/cli-kit/dist/public/node/json-output-schema.d.ts@@ -1,6 +1,6 @@
import { zodToJsonSchema } from 'zod-to-json-schema';
import type { ZodTypeAny, z } from 'zod';
-export { formatJsonOutputTimestamp, jsonOutputTimestampSchema } from '../common/json-output-schema.js';
+export { formatJsonOutputTimestamp, jsonOutputTimestampSchema, jsonOutputStoreDomainSchema, } from '../common/json-output-schema.js';
interface JsonOutputSchemaDefinition<TSchema extends ZodTypeAny = ZodTypeAny> {
readonly name: string;
readonly schema: TSchema;
packages/cli-kit/dist/public/node/graphiql/server.d.ts@@ -27,13 +27,14 @@ export declare function resolveGraphiQLKey(providedKey: string | undefined, apiS
* - `getToken` may return a cached token; the proxy calls it for every request.
* - `refreshToken` (optional) is invoked when the upstream Admin API returns 401.
* When omitted, the proxy falls back to calling `getToken` again on 401.
+ * - Both operations receive a cancellation signal to pass to token requests.
*
* Implementations must throw `TokenRefreshError` (or any thrown error) when the
* token cannot be obtained; the proxy renders the unauthorized template in that case.
*/
export interface TokenProvider {
- getToken: () => Promise<string>;
- refreshToken?: () => Promise<string>;
+ getToken: (signal?: AbortSignal) => Promise<string>;
+ refreshToken?: (signal?: AbortSignal) => Promise<string>;
}
/**
* Optional app-specific context, used to render the app pill and scopes note in the
@@ -65,6 +66,10 @@ export interface SetupGraphiQLServerOptions {
* interactive UI.
*/
protectMutations?: boolean;
+ /** Called for request failures that leave the server available for subsequent requests. */
+ onRequestError?: (message: string) => void;
+ /** Routes diagnostics through command events and leaves readiness output to the session. */
+ json?: boolean;
}
export declare const MUTATIONS_BLOCKED_MESSAGE = "Mutations are disabled. Re-run with --allow-mutations to enable mutations.";
/**
packages/cli-kit/dist/public/node/graphiql/session.d.ts@@ -22,6 +22,7 @@ export interface RunGraphiQLSessionOptions {
additionalReadyMessages?: OutputMessage[];
abortSignal?: AbortSignal;
stdout?: Writable;
+ outputFormat?: 'text' | 'json';
}
/**
* Generates a random key suitable for authenticating a single local GraphiQL session.
|
WHY are these changes introduced?
Agents need to discover when GraphiQL is ready and follow failures and shutdown without parsing terminal output.
Fixes https://github.com/shop/issues-develop/issues/24313
Fixes https://github.com/shop/issues-develop/issues/24316
WHAT is this pull request doing?
Adds
--jsontoapp graphiqlandstore graphiql. Both share typed JSONL lifecycle records (starting,ready,stopped) and schema discovery. The ready record includes the authenticated local URL, store, API context, app context, and mutation permissions. Diagnostics use stderr; fatal failures end stdout with the standard error envelope. There is no finite success result.The shared GraphiQL session waits for the server to listen and closes active connections and aborts upstream requests on shutdown. Launcher signal delegation allows cleanup to finish before exiting. SIGINT, SIGTERM, and SIGQUIT exit with 130, 143, and 131. Existing authentication, store mutation protection, and HTTP response payloads are preserved. Browser opening remains enabled unless
--no-inputis supplied, independently of output format.Updates generated help, manifests, and command documentation. Removes both commands from the JSON output exception list.
How to manually test your changes?
pnpm shopify store graphiql --store <shop.myshopify.com> --json --no-input > /tmp/graphiql.jsonl 2> /tmp/graphiql-diagnostics.jsonl. Open theready.urlin a browser and confirm GraphiQL works. Try a mutation with the default permissions: it should remain blocked and produce a diagnostic on stderr.stoppedrecord, exit code 130, and a closed local server.pnpm shopify app graphiql --path <app-path> --store <shop.myshopify.com> --json. Confirm browser opening, the app context inready, and shutdown. Repeat without--jsonto check text output.--json-schema; authentication and server startup should not run.Checklist
minor) and added a changeset